#include "hexdump.h"

#include <string.h>
#include <ctype.h>
#include <stdlib.h>

void fhex_dump(FILE *stream, void *data, long offset, size_t size) {
	/* dumps size bytes of *data to stdout. Looks like:
	 * [0000] 75 6E 6B 6E 6F 77 6E 20
	 *                  30 FF 00 00 00 00 39 00 unknown 0.....9.
	 * (in a single line of course)
	 */

	unsigned int u_offset;//offset can be negative. This is a calculated positive offset
	unsigned int x = 0;
	size_t bytes_to_dump;
	unsigned char *p;
	unsigned char c;
	size_t n;
	char bytestr[4] = { 0 };
	char addrstr[10] = { 0 };
	char hexstr[16 * 3 + 5] = { 0 };
	char charstr[16 * 1 + 5] = { 0 };

	//calc u_offset: if offset > 0: u_offset = offset; else: u_offset = size-labs(offset)
	u_offset = (offset>=0?(unsigned int)offset:size-(unsigned int)labs(offset));
	p = data+u_offset;
	bytes_to_dump = size-u_offset;

	for (n = 1; n <= bytes_to_dump; n++) {
		if (n % 16 == 1) {
			/* store address for this line */
			snprintf(addrstr, sizeof(addrstr), "%.6lX", x + offset);
		}

		c = *p;
		if (isprint(c) == 0) {
			c = '.';
		}

		/* store hex str (for left side) */
		snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
		strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);

		/* store char str (for right side) */
		snprintf(bytestr, sizeof(bytestr), "%c", c);
		strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1);

		if (n % 16 == 0) {
			/* line completed */
			printf("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
			hexstr[0] = 0;
			charstr[0] = 0;
		} else if (n % 8 == 0) {
			/* half line: add whitespaces */
			strncat(hexstr, "  ", sizeof(hexstr) - strlen(hexstr) - 1);
			strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1);
		}
		p++; /* next byte */
		x++;
	}

	if (strlen(hexstr) > 0) {
		/* print rest of buffer if not empty */
		fprintf(stream, "[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
	}
}

void hex_dump(void *data, long offset, size_t size) {
	fhex_dump(stdout,data,offset,size);
}

